﻿package com.game.engine.phys
{
    import base.BaseObject;
    
    import com.dusk.util.ArrayUtil;
    import com.game.engine.nape.BodyTypeConst;
    import com.game.engine.nape.Nape;
    import com.game.engine.nape.utils.BodyUserData;
    import com.game.engine.nape.utils.CollisionGroup;
    
    import flash.geom.Rectangle;
    
    import nape.callbacks.CbType;
    import nape.geom.Vec2;
    import nape.phys.Body;
    import nape.phys.BodyType;
    import nape.phys.Material;
    import nape.shape.Circle;
    import nape.shape.Polygon;
    import nape.shape.Shape;
    import nape.space.Space;
    
    public class RigidBody
    {

        private var _allowRotation:Boolean;
        private var _body:Body;
        private var _Velocity:Vector2D = Vector2D.zero;
        private var _material:Material;
        
        private var _collisionGroup:int = 1;
        private var _sensorGroup:int = 1;
        private var _collisionMask:int = -1;
        private var _sensorMask:int = -1;
        
        private var _gravMass:Number;
        private var _type:BodyType;
        private var _oldP:Vector2D = new Vector2D();
        private var _oldRotation:Number = 0;
        private var _position:Vector2D;
        private var bType:String;
        private var _collisionMaskArr:Array = [];
        private var _space:Space;
        private var _active:Boolean;
        public var once:int = -1;
        private var _rotation:Number;
        public var rotationMirror:Boolean;
        public var noUpdateGameObjectPos:Boolean;
        private var _fluidEnabled:Boolean;
        private var _fluidGroup:int;
        public var noTrigger:Boolean;
        private var _lastRec:Rectangle;
        private var _deleted:Boolean;
        
        private var _gameObject:BaseObject;

        public function RigidBody(bodyType:String, pos:Vector2D)
        {
            super();
            var type:BodyType;
            bType = bodyType;
            if (bodyType == BodyTypeConst.ST)
            {
                type = BodyType.STATIC;
            }
            else if (bodyType == BodyTypeConst.DY)
            {
                type = BodyType.DYNAMIC;
            }
            else if (bodyType == BodyTypeConst.KC)
            {
                type = BodyType.KINEMATIC;
            }
            else
            {
                throw new Error("Invalid body type");
            }
            _body = new Body(type, new Vec2(pos.x, pos.y));
            _position = pos.clone();
        }
        
        public function setGameObject(object:BaseObject):void
        {
            _gameObject = object;
        }

        public function get lastRec():Rectangle
        {
            return _lastRec;
        }

        public function get fluidEnabled():Boolean
        {
            return _fluidEnabled;
        }

        public function set fluidEnabled(isEnable:Boolean):void
        {
            _fluidEnabled = isEnable;
            for (var i:int = 0; i < _body.shapes.length; i++)
            {
                _body.shapes.at(i).fluidEnabled = _fluidEnabled;
            }
        }

        public function get rotation():Number
        {
            return body.rotation;
        }

        public function set rotation(_arg_1:Number):void
        {
            _rotation = _arg_1;
            body.rotation = _arg_1;
        }

        public function get active():Boolean
        {
            return _active;
        }

        public function set active(isActive:Boolean):void
        {
            _active = isActive;
            if (!_space)
            {
                _space = body.space;
            }
            body.space = active ? _space : null;
        }

        public function get position():Vector2D
        {
            _position.setXY(_body.position.x, _body.position.y);
            return _position;
        }

        public function set position(vec:Vector2D):void
        {
            _position = vec;
            _body.position.setxy(vec.x, vec.y);
        }

        public function positionXY(posX:Number, posY:Number):void
        {
            _position.setXY(posX, posY);
            _body.position.setxy(posX, posY);
        }

        public function get type():BodyType
        {
            return _type;
        }

        public function set type(bodyType:BodyType):void
        {
            _type = bodyType;
            body.type = bodyType;
        }

        public function awake():void
        {
            allowRotation = false;
            var data:BodyUserData = new BodyUserData();
            data.body = this;
            data.gameObject = _gameObject;
            _body.userData.data = data;
            active = true;
        }

        public function get gravMass():Number
        {
            return body.gravMass;
        }

        public function set gravMass(mass:Number):void
        {
            body.gravMass = mass;
        }

        public function get collisionMask():Number
        {
            return _collisionMask;
        }

        public function set collisionMask(mask:Number):void
        {
            _collisionMask = mask;
            for (var i:int = 0; i < _body.shapes.length; i++)
            {
                _body.shapes.at(i).filter.collisionMask = _collisionMask;
            }
        }

        public function addCollisionMask(mask:int):void
        {
            if (_collisionMaskArr.indexOf(mask) == -1)
            {
                _collisionMaskArr.push(mask);
                reSetCollisionMask();
            }
        }

        public function removeCollisionMask(mask:int):void
        {
            ArrayUtil.removeElement(_collisionMaskArr, mask, true);
            reSetCollisionMask();
        }

        private function reSetCollisionMask():void
        {
            if(_collisionMaskArr.length == 0)
            {
                _collisionMask = CollisionGroup.NONE;
                return;
            }
            var m:int = _collisionMaskArr[0];
            for (var i:int = 1; i < _body.shapes.length; i++)
            {
                m |= _collisionMaskArr[i];
            }
            collisionMask = m;
        }

        public function get width():int
        {
            return body.bounds.width;
        }

        public function get fluidGroup():int
        {
            return _fluidGroup;
        }

        public function set fluidGroup(group:int):void
        {
            _fluidGroup = group;
            for (var i:int = 0; i < _body.shapes.length; i++)
            {
                _body.shapes.at(i).filter.fluidGroup = _fluidGroup;
            }
        }

        public function get collisionGroup():int
        {
            return _collisionGroup;
        }

        public function set collisionGroup(group:int):void
        {
            _collisionGroup = group;
            for (var i:int = 0; i < _body.shapes.length; i++)
            {
                _body.shapes.at(i).filter.collisionGroup = _collisionGroup;
            }
        }

        public function set sensorGroup(group:int):void
        {
            _sensorGroup = group;
            for (var i:int = 0; i < _body.shapes.length; i++)
            {
                _body.shapes.at(i).filter.sensorGroup = group;
            }
        }

        public function get sensorGroup():int
        {
            return _sensorGroup;
        }

        public function set sensorMask(mask:int):void
        {
            _sensorMask = mask;
            for (var i:int = 0; i < _body.shapes.length; i++)
            {
                _body.shapes.at(i).filter.sensorMask = _sensorMask;
            }
        }

        public function get sensorMask():int
        {
            return _sensorMask;
        }

        public function get material():Material
        {
            return _material;
        }

        public function set material(ma:Material):void
        {
            _material = ma;
            body.setShapeMaterials(_material);
        }

        public function get body():Body
        {
            return _body;
        }

        public function get Velocity():Vector2D
        {
            _Velocity.setXY(_body.velocity.x, _body.velocity.y);
            return _Velocity;
        }

        public function set Velocity(vec:Vector2D):void
        {
            _Velocity.setXY(vec.x, vec.y);
            _body.velocity.set(vec.toVec2);
//            if (!isNaN(vec.x))
//            {
//                _body.velocity.x = vec.x;
//            }
//            if (!isNaN(vec.y))
//            {
//                _body.velocity.y = vec.y;
//            }
        }

        public function get allowRotation():Boolean
        {
            return _allowRotation;
        }

        public function set allowRotation(isAllow:Boolean):void
        {
            _allowRotation = isAllow;
            body.allowRotation = isAllow;
        }

        public function set allowMovement(isAllow:Boolean):void
        {
            if (body)
            {
                body.allowMovement = isAllow;
            }
        }

        public function get allowMovement():Boolean
        {
            return body.allowMovement;
        }

        public function addCircleCollider(r:Number, x:Number, y:Number, ma:Material=null):void
        {
            var cir:Circle = new Circle(r, null, ma);
            cir.translate(new Vec2(x, y));
            _body.shapes.add(cir);
            initShapeGroupMask(cir);
            initSpace();
        }

        private function initSpace():void
        {
            if (_body.space)
            {
                return;
            }
            _body.space = Nape.getIns().space;
        }

        public function addBoxCollider(x:Number, y:Number, w:Number, h:Number, ma:Material=null):void
        {
            var rec:Polygon = new Polygon(Polygon.rect(x,y,w,h), ma);
            _body.shapes.add(rec);
            initShapeGroupMask(rec);
            initSpace();
        }

        private function initShapeGroupMask(s:Shape):void
        {
            s.filter.collisionGroup = collisionGroup;
            s.filter.collisionMask = collisionMask;
            s.filter.sensorGroup = sensorGroup;
            s.filter.sensorMask = sensorMask;
        }

        public function addViewRange(x:Number, y:Number, w:Number, h:Number):void
        {
            var polygon:Polygon = new Polygon(Polygon.rect(x,y,w, h), null);
            _body.shapes.add(polygon);
            polygon.sensorEnabled = true;
            polygon.filter.collisionGroup = 0;
            initSpace();
        }

        public function setSensor(isEnable:Boolean, group:int, mask:int):void
        {
            _sensorGroup = group;
            _sensorMask = mask;
            for (var i:int = 0; i < _body.shapes.length; i++)
            {
                _body.shapes.at(i).sensorEnabled = isEnable;
                _body.shapes.at(i).filter.sensorGroup = _sensorGroup;
                _body.shapes.at(i).filter.sensorMask = _sensorMask;
            }
        }

        public function removeFluid():void
        {
            for (var i:int = 0; i < body.shapes.length; i++)
            {
                body.shapes.at(i).fluidEnabled = false;
                body.shapes.at(i).filter.fluidGroup = 0;
                body.shapes.at(i).filter.fluidMask = 0;
            }
        }

        /*override protected function doInAdvance(_arg_1:Number):void
        {
            var _local_2:* = null;
            if (noUpdateGameObjectPos)
            {
                return;
            }
            super.doInAdvance(_arg_1);
            if (!updateEnabled)
            {
                if (bType != "st")
                {
                    _body.position = new Vec2(gameObject.x, gameObject.y);
                }
                return;
            }
            if (!(_oldP.x == _body.position.x && _oldP.y == _body.position.y))
            {
                if (gameObject)
                {
                    gameObject.Position = new Vector2D(_body.position.x, _body.position.y);
                }
                _oldP.x = _body.position.x;
                _oldP.y = _body.position.y;
            }
            if (_oldRotation != body.rotation)
            {
                if (gameObject)
                {
                    gameObject.rotation = MathUtils.hudu2JiaoDu(body.rotation);
                }
                _oldRotation = body.rotation;
            }
            if (Velocity.length > 0 && allowRotation)
            {
                body.rotation = Velocity.angle;
                _oldRotation = body.rotation;
                if (gameObject)
                {
                    _local_2 = Velocity.clone();
                    _local_2.normalize();
                    if (rotationMirror)
                    {
                        gameObject.scaleX = -1;
                        gameObject.rotation = -(180 - _local_2.angle2);
                    }
                    else
                    {
                        gameObject.SetDirection(_local_2);
                    }
                }
            }
        }*/

        public function addCbTypes(cbType:CbType):void
        {
            body.cbTypes.add(cbType);
        }

        public function setSize(newRect:Rectangle):void
        {
            if (_lastRec && newRect)
            {
                if (_lastRec.equals(newRect))
                {
                    return;
                }
            }
            _lastRec = newRect;
            var _local_7:Shape = body.shapes.at(body.shapes.length - 1);
            var _local_2:Number = rotation;
            rotation = 0;
            var _local_10:Number = newRect.width / _local_7.bounds.width;
            var _local_8:Number = newRect.height / _local_7.bounds.height;
            _local_7.scale(_local_10, _local_8);
            _local_7.translate(new Vec2((newRect.x - _local_7.bounds.x) + position.x, (newRect.y - _local_7.bounds.y) + position.y));
            rotation = _local_2;
        }

        public function destroy():void
        {
            if (body)
            {
                /*if (collisionGroup == CollisionGroup.FLOOR)
                {
                    Map.getIns().removeFloor(this);
                }*/
                if (!body.space)
                {
                    body.space = Nape.getIns().space;
                }
                body.space.bodies.remove(body);
                _body = null;
            }
        }

        public function addPolygon(points:Vector.<Vector2D>, _arg_2:Material=null):void
        {
            var vec2s:Vector.<Vec2> = new Vector.<Vec2>();
            for each(var p:Vector2D in points)
            {
                vec2s.push(new Vec2(p.x,p.y));
            }
            var polygon:Polygon = new Polygon(vec2s, _arg_2);
            _body.shapes.add(polygon);
            _body.align();
            initShapeGroupMask(polygon);
            initSpace();
        }

        public function enableGrav(isEnable:Boolean):void
        {
            if (isNaN(_gravMass))
            {
                _gravMass = _body.gravMass;
            }
            gravMass = isEnable ? _gravMass : 0;
        }

        public function allowMove(_arg_1:Boolean):void
        {
            if (_deleted)
            {
                return;
            }
            if (_arg_1 == false)
            {
                allowMovement = false;
                Velocity = Vector2D.zero;
                enableGrav(false);
            }
            else
            {
                allowMovement = true;
                enableGrav(true);
            }
        }

        public function setFluidProperties(_arg_1:Object):void
        {
            var _local_3:int;
            var _local_2:* = null;
            _local_3 = 0;
            while (_local_3 < body.shapes.length)
            {
                _local_2 = body.shapes.at(_local_3);
                _local_2.fluidProperties.density = _arg_1.density;
                _local_2.fluidProperties.viscosity = _arg_1.viscosity;
                _local_2.fluidProperties.gravity = _arg_1.gravity;
                _local_3++;
            }
        }

        public function reCreateBodyCircle(_arg_1:Number):void
        {
            var _local_3:int;
            var _local_2:* = null;
            _local_3 = 0;
            while (_local_3 < _body.shapes.length)
            {
                _local_2 = _body.shapes.at(_local_3);
                if (_local_2 && _local_2.isCircle())
                {
                    Circle(_local_2).scale(_arg_1 / _local_2.bounds.width, _arg_1 / _local_2.bounds.width);
                    return;
                }
                _local_3++;
            }
        }
    }
}